package services

import (
	"encoding/json"
	"github.com/pkg/errors"
	"go.didapinche.com/foundation/apisix-dashboard/internal/app/models"
	"go.didapinche.com/foundation/apisix-dashboard/internal/app/repository"
	"go.etcd.io/etcd/clientv3"
	"go.uber.org/zap"
	"strings"
	"time"
)

type ConsumerService interface {
	Get(key, env string) (*models.Consumer, error)
	List(name, env string) ([]*models.Consumer, error)
	Create(consumer *models.Consumer, env string) error
	Update(consumer *models.Consumer, env string) error
	Delete(key, env string) error
	GetName(name, env string) (bool, error)
	Syn(consumer *models.Consumer, env []string) error
}

type consumerService struct {
	etcd   repository.EtcdRepository
	log    *zap.Logger
	client map[string]*clientv3.Client
}

func NewConsumerService(
	etcd repository.EtcdRepository,
	log *zap.Logger,
	client map[string]*clientv3.Client,
) ConsumerService {
	return &consumerService{
		etcd:   etcd,
		log:    log,
		client: client,
	}
}

//名字及id
func (s consumerService) Get(key, env string) (*models.Consumer, error) {
	param, err := s.etcd.Get(s.client[env], "/apisix/consumers/"+key)
	if err != nil {
		return nil, errors.Wrap(err, "call etcd.Get failed")
	}
	u := new(models.Consumer)
	err = json.Unmarshal([]byte(param), &u)
	if err != nil {
		return nil, errors.Wrap(err, "call json.Unmarshal failed")
	}
	return u, nil
}

func (s consumerService) List(name, env string) ([]*models.Consumer, error) {
	params, err := s.etcd.List(s.client[env], "/apisix/consumers/")
	if err != nil {
		return nil, errors.Wrap(err, "call etcd.Get(s.client[env] /apisix/upstreams) failed")
	}
	us := make([]*models.Consumer, 0)
	for i := 0; i < len(params); i++ {
		u := new(models.Consumer)
		err = json.Unmarshal([]byte(params[i]), &u)
		if err != nil {
			s.log.Info("上游解析失败")
		} else {
			if name != "" && strings.Contains(u.ID, name) {
				us = append(us, u)
			}
			if name == "" {
				us = append(us, u)
			}
		}
	}
	return us, nil
}

func (s consumerService) Create(consumer *models.Consumer, env string) error {

	consumer.CreateTime = time.Now().Unix()
	consumer.UpdateTime = time.Now().Unix()
	str, err := json.Marshal(consumer)
	if err != nil {
		return errors.Wrap(err, "call json.Marshal failed")
	}
	if err := s.etcd.Create(s.client[env], "/apisix/consumers/"+consumer.ID, string(str)); err != nil {
		return errors.Wrap(err, "call etcd.Create failed")
	}
	return nil
}

func (s consumerService) Update(consumer *models.Consumer, env string) error {
	consumer.CreateTime = time.Now().Unix()
	consumer.UpdateTime = time.Now().Unix()
	str, err := json.Marshal(consumer)
	if err != nil {
		return errors.Wrap(err, "call json.Marshal failed")
	}
	if err := s.etcd.Update(s.client[env], "/apisix/consumers/"+consumer.ID, string(str)); err != nil {
		return errors.Wrap(err, "call etcd.Update failed")
	}
	return nil
}

func (s consumerService) Delete(key, env string) error {
	if err := s.etcd.Delete(s.client[env], "/apisix/consumers/"+key); err != nil {
		return errors.Wrap(err, "call etcd.Delete failed")
	}
	return nil
}

func (s consumerService) GetName(name, env string) (bool, error) {
	params, err := s.etcd.List(s.client[env], "/apisix/consumers/")
	if err != nil {
		return true, errors.Wrap(err, "call etcd.Get failed")
	}
	for i := range params {
		u := new(models.Consumer)
		err = json.Unmarshal([]byte(params[i]), &u)
		if err != nil {
			s.log.Error("路由名字解析失败")
		} else {
			if name == u.ID {
				return true, nil
			}
		}
	}
	return false, nil
}

func (s consumerService) Syn(consumer *models.Consumer, env []string) error {
	for _, e := range env {
		if err := s.Create(consumer, e); err != nil {
			return errors.Wrap(err, "call consumerService.create error")
		}
	}
	return nil
}
